import ctypes
import ctypes.wintypes as wintypes
import threading
import time
import os
import sys
import win32gui
import win32con
import win32api
import win32process
import msvcrt
import os

# 用户设定
host_window_name = "Host Window"  # 默认宿主窗口名称
target_window_class = "DIBFullViewClass"  # 默认目标窗口类名

# 全局变量
class_name = "HostWindowClass"
top_most = True
g_rect_window_before_fullscreen = (0, 0, 0, 0)
g_b_fullscreen = False
g_got_target = False
g_debug = False
h_target = 0
h_host = 0


def db_o(s):
    if g_debug:
        print(f"\n[Debug]{s}\n(BKR) $", end='')


def host_wnd_proc(hwnd, msg, wparam, lparam):
    global g_b_fullscreen, g_rect_window_before_fullscreen, h_target, h_host, g_got_target

    if msg == win32con.WM_SIZE:
        if h_target and g_got_target:
            win32gui.InvalidateRect(h_target, None, True)
            win32gui.UpdateWindow(h_target)
            rect = win32gui.GetClientRect(hwnd)
            win32gui.SetWindowPos(h_target, 0, 0, 0, rect[2], rect[3],
                                  win32con.SWP_NOZORDER | win32con.SWP_FRAMECHANGED)
        win32gui.SetWindowPos(h_host, 0, 0, 0, 0, 0,
                              win32con.SWP_NOZORDER | win32con.SWP_FRAMECHANGED |
                              win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)
        return 0

    elif msg == win32con.WM_KEYDOWN:
        if wparam == win32con.VK_ESCAPE:
            g_b_fullscreen = not g_b_fullscreen
            if g_b_fullscreen:
                g_rect_window_before_fullscreen = win32gui.GetWindowRect(hwnd)
                win32gui.SetWindowLong(hwnd, win32con.GWL_STYLE, win32con.WS_POPUP | win32con.WS_VISIBLE)
                win32gui.SetWindowPos(hwnd, win32con.HWND_TOP,
                                      0, 0,
                                      win32api.GetSystemMetrics(win32con.SM_CXSCREEN),
                                      win32api.GetSystemMetrics(win32con.SM_CYSCREEN),
                                      win32con.SWP_FRAMECHANGED)
            else:
                win32gui.SetWindowLong(hwnd, win32con.GWL_STYLE, win32con.WS_OVERLAPPEDWINDOW | win32con.WS_VISIBLE)
                win32gui.SetWindowPos(hwnd, 0,
                                      g_rect_window_before_fullscreen[0],
                                      g_rect_window_before_fullscreen[1],
                                      g_rect_window_before_fullscreen[2] - g_rect_window_before_fullscreen[0],
                                      g_rect_window_before_fullscreen[3] - g_rect_window_before_fullscreen[1],
                                      win32con.SWP_FRAMECHANGED | win32con.SWP_NOZORDER)
            return 0

    elif msg == win32con.WM_DESTROY:
        win32gui.PostQuitMessage(0)
        return 0

    elif msg == win32con.WM_KEYDOWN:
        # 检测键盘钩子
        hHook = ctypes.windll.user32.GetWindowsHookEx(win32con.WH_KEYBOARD_LL)
        if hHook:
            ctypes.windll.user32.UnhookWindowsHookEx(hHook)
            db_o("Removed keyboard hook")

    elif msg == win32con.WM_KEYDOWN:
        # 确保消息传递到目标窗口
        if h_target and g_got_target:
            win32gui.PostMessage(h_target, msg, wparam, lparam)

    return win32gui.DefWindowProc(hwnd, msg, wparam, lparam)


def create_host_window(h_target):
    wc = win32gui.WNDCLASS()
    wc.lpfnWndProc = host_wnd_proc
    wc.hInstance = win32api.GetModuleHandle(None)
    wc.lpszClassName = class_name
    wc.hbrBackground = win32gui.GetStockObject(win32con.WHITE_BRUSH)
    class_atom = win32gui.RegisterClass(wc)

    hwnd = win32gui.CreateWindowEx(
        0, class_name, host_window_name,
        win32con.WS_POPUP | win32con.WS_OVERLAPPEDWINDOW,
        win32con.CW_USEDEFAULT, win32con.CW_USEDEFAULT,
        800, 600, None, None, win32api.GetModuleHandle(None), None
    )

    win32gui.SetWindowLong(hwnd, win32con.GWL_USERDATA, h_target)
    return hwnd


def embed_window():
    global h_target, h_host

    if not h_target or not win32gui.IsWindow(h_target) or not win32gui.IsWindowVisible(h_target) or win32gui.GetParent(
            h_target):
        return

    style = win32gui.GetWindowLong(h_target, win32con.GWL_STYLE)
    ex_style = win32gui.GetWindowLong(h_target, win32con.GWL_EXSTYLE)

    style &= ~win32con.WS_POPUP
    style |= win32con.WS_CHILD
    ex_style &= ~win32con.WS_EX_TOPMOST

    win32gui.SetWindowLong(h_target, win32con.GWL_STYLE, style)
    win32gui.SetWindowLong(h_target, win32con.GWL_EXSTYLE, ex_style)

    win32gui.SetParent(h_target, h_host)

    win32gui.InvalidateRect(h_target, None, True)
    win32gui.UpdateWindow(h_target)
    rect = win32gui.GetClientRect(h_host)
    win32gui.SetWindowPos(h_target, 0, rect[0], rect[1], rect[2], rect[3],
                          win32con.SWP_NOZORDER | win32con.SWP_FRAMECHANGED)
    win32gui.SetWindowPos(h_host, 0, 0, 0, 0, 0,
                          win32con.SWP_NOZORDER | win32con.SWP_FRAMECHANGED |
                          win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)

    # 恢复键盘输入
    ctypes.windll.user32.BlockInput(False)
    win32gui.EnableWindow(h_target, True)


def con_in():
    global top_most, g_debug

    print("PyScreenControlBreaker-alpha-0.0.1  Copyright (C) 2025  VekarisWesion")
    print("This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.")
    print("This is free software, and you are welcome to redistribute it")
    print("under certain conditions; type `show c' for details.")
    print()
    print("Command options:")
    print("  PW       - View project webpage")
    print("  top      - Toggle window top-most state")
    print("  debug    - Toggle debug mode")
    print("Press Ctrl + C to exit.")
    print()

    while True:
        print("(BKR) $", end=' ')
        cmd = input().strip().lower()
        if cmd == "pw":
            os.startfile("https://gitee.com/vekariswesion/character-world-screen-control-breaker")
            print("Success")
        elif cmd == "top":
            top_most = not top_most
            print(f"Success {'On' if top_most else 'Off'}")
        elif cmd == "debug":
            g_debug = not g_debug
            print(f"Success {'On' if g_debug else 'Off'}")
        else:
            print("Unknown command")
        time.sleep(0.3)


def find_wd():
    global h_target, h_host, g_got_target

    while True:
        while not h_target:
            h_target = win32gui.FindWindow(target_window_class, None)
            time.sleep(0.05)

        db_o("finded")
        g_got_target = True
        win32gui.ShowWindow(h_host, win32con.SW_SHOW)
        embed_window()

        while g_got_target:
            time.sleep(0.25)


def keyboard_defender():
    while True:
        if h_target:
            # 定期检查并恢复键盘状态
            ctypes.windll.user32.BlockInput(False)
            win32gui.EnableWindow(h_target, True)
        time.sleep(1)


def main():
    global h_host, h_target, g_got_target, top_most

    # 创建控制台输入线程
    console_thread = threading.Thread(target=con_in, daemon=True)
    console_thread.start()

    defender_thread = threading.Thread(target=keyboard_defender, daemon=True)
    defender_thread.start()

    # 创建宿主窗口
    h_host = create_host_window(h_target)
    win32gui.ShowWindow(h_host, win32con.SW_HIDE)

    # 创建查找目标窗口线程
    find_thread = threading.Thread(target=find_wd, daemon=True)
    find_thread.start()

    # 主消息循环
    while True:
        msg = win32gui.GetMessage(None, 0, 0)
        if msg[0] == 0:
            break

        win32gui.TranslateMessage(msg[1])
        win32gui.DispatchMessage(msg[1])

        if g_got_target:
            if not h_target or not win32gui.IsWindow(h_target):
                g_got_target = False
                if h_host and win32gui.IsWindow(h_host):
                    win32gui.ShowWindow(h_host, win32con.SW_HIDE)
                continue

            if h_host and win32gui.IsWindow(h_host):
                win32gui.SetWindowPos(h_host,
                                      win32con.HWND_TOPMOST if top_most else win32con.HWND_NOTOPMOST,
                                      0, 0, 0, 0,
                                      win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)

            if h_target and win32gui.IsWindow(h_target) and h_host and win32gui.IsWindow(h_host):
                style = win32gui.GetWindowLong(h_target, win32con.GWL_STYLE)
                if style != 0:
                    style &= ~win32con.WS_POPUP
                    style |= win32con.WS_CHILD
                    win32gui.SetWindowLong(h_target, win32con.GWL_STYLE, style)
                    win32gui.SetWindowPos(h_target, win32con.HWND_NOTOPMOST,
                                          0, 0, 0, 0,
                                          win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)

                    if win32gui.GetParent(h_target) != h_host:
                        win32gui.SetParent(h_target, h_host)


if __name__ == "__main__":
    main()
